#ifdef ANDROID
#include <jni.h>
#include <android/log.h>

#include <string>
#include "stdio.h"
#include "thread"
#include <stdatomic.h>

#ifdef __cplusplus
extern "C"
{
#endif
#include "xm_client.h"
#ifdef __cplusplus
}
#endif

using namespace std;

#define JNI_API(retType,funName,...) extern "C"  JNIEXPORT retType Java_com_test_uimremote_jni_XmClient_##funName(JNIEnv* env, jclass cls,##__VA_ARGS__)
#define XmCallBackSign "com/test/uimremote/jni/XmClient$XmCallBack"
#define TAG    "sim-jni" // 这个是自定义的LOG的标识
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型

extern int start_main(void);
extern atomic_int exit_flag;

string stringFromJstring(JNIEnv *env,jstring jstr){
    if(!env || !jstr){
        LOGD("invalid args");
        return "";
    }
    const char *field_char = env->GetStringUTFChars(jstr, 0);
    string ret(field_char,env->GetStringUTFLength(jstr));
    env->ReleaseStringUTFChars(jstr, field_char);
    return ret;
}
string stringFromJbytes(JNIEnv *env,jbyteArray jbytes){
    if(!env || !jbytes){
        LOGD("invalid args");
        return "";
    }
    jbyte *bytes = env->GetByteArrayElements(jbytes, 0);
    string ret((char *)bytes,env->GetArrayLength(jbytes));
    env->ReleaseByteArrayElements(jbytes,bytes,0);
    return ret;
}
string stringFieldFromJava(JNIEnv *env,  jobject jdata,jfieldID jid){
    if(!env || !jdata || !jid){
        LOGD("invalid args");
        return "";
    }
    jstring field_str = (jstring)env->GetObjectField(jdata,jid);
    auto ret = stringFromJstring(env,field_str);
    env->DeleteLocalRef(field_str);
    return ret;
}

string bytesFieldFromJava(JNIEnv *env,  jobject jdata,jfieldID jid){
    if(!env || !jdata || !jid){
        LOGD("invalid args");
        return "";
    }
    jbyteArray jbufArray = (jbyteArray)env->GetObjectField(jdata, jid);
    string ret = stringFromJbytes(env,jbufArray);
    env->DeleteLocalRef(jbufArray);
    return ret;
}

jstring jstringFromString(JNIEnv* env, const char* pat) {
    return (jstring)env->NewStringUTF(pat);
}

jbyteArray jbyteArrayFromString(JNIEnv* env, const char* pat,int len = 0){
    if(len <= 0){
        len = strlen(pat);
    }
    jbyteArray jarray = env->NewByteArray(len);
    env->SetByteArrayRegion(jarray, 0, len, (jbyte *)(pat));
    return jarray;
}

static JavaVM *s_jvm = nullptr;

template <typename FUN>
void doInJavaThread(FUN &&fun){
    JNIEnv *env;
    int status = s_jvm->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (status != JNI_OK) {
        if (s_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) {
            return;
        }
    }
    fun(env);
    if (status != JNI_OK) {
        //Detach线程
        s_jvm->DetachCurrentThread();
    }
}

#define emitEvent(delegate,method,argFmt,...) \
{ \
    doInJavaThread([&](JNIEnv* env) { \
        static jclass cls = env->GetObjectClass(delegate); \
        static jmethodID jmid = env->GetMethodID(cls, method, argFmt); \
        jobject localRef = env->NewLocalRef(delegate); \
        if(localRef){ \
            env->CallVoidMethod(localRef, jmid, ##__VA_ARGS__); \
        }else{ \
            WarnL << "弱引用已经释放:" << method << " " << argFmt; \
        }\
    }); \
}

/*
 * 加载动态库
 */
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    s_jvm = vm;
    //设置日志
    return JNI_VERSION_1_6;
}

static pthread_t s_tread_id = 0;

/*
 * 卸载动态库
 */
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved){
    LOGD("Library unload");
    if(s_tread_id){
        pthread_kill(s_tread_id,SIGINT);
    }
}

JNI_API(jboolean,start){
LOGD("********************************* start");
    start_main();
LOGD("********************************* start ********************");
   return (jboolean) 0;
}

JNI_API(jboolean,stop){
LOGD("------------------------------------ stop");
exit_flag = 1;
return (jboolean) 0;
}


JNI_API(jboolean, init, jstring domain, jstring ip, jchar port) {
    LOGD("init调用！！！ domain:%s, ip:%s, port:%d", domain, ip, port);
    std::string domainStr = stringFromJstring(env, domain);
    string ipStr = stringFromJstring(env, ip);
    LOGD("domain:%s, ip:%s, port:%d", domain, ip, port);
    Xm_Data_Init(domainStr.c_str(), ipStr.c_str(), port);
    return (jboolean) 0;
}

JNI_API(void, setCalback, jobject callback) {
    jobject globalWeakRef = env->NewWeakGlobalRef(callback);

}
#endif //ANDROID